package cn.mini.mybatis.mybatis.builder.xml;

import cn.mini.mybatis.mybatis.builder.BaseBuilder;
import cn.mini.mybatis.mybatis.builder.MapperBuilderAssistant;
import cn.mini.mybatis.mybatis.io.Resources;
import cn.mini.mybatis.mybatis.session.Configuration;
import lombok.SneakyThrows;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import java.io.Reader;
import java.util.List;


/**
 * XMLMapperBuilder 类用于解析 MyBatis 的 Mapper XML 文件，
 * 将文件中的配置信息转换为 MappedStatement 对象并添加到 Configuration 中。
 */
public class XMLMapperBuilder extends BaseBuilder {

    /**
     * 用于读取 Mapper XML 文件的字符输入流
     */
    private Reader reader;
    /**
     * Mapper XML 文件的资源路径
     */
    private String resource;
    /**
     * Mapper 构建辅助类，用于协助构建 MappedStatement 对象
     */
    private MapperBuilderAssistant builderAssistant;

    /**
     * 构造函数，初始化 XMLMapperBuilder 对象
     *
     * @param reader 用于读取 Mapper XML 文件的字符输入流
     * @param resource Mapper XML 文件的资源路径
     * @param configuration MyBatis 的配置对象
     */
    public XMLMapperBuilder(Reader reader, String resource , Configuration configuration) {
        super(configuration);
        this.reader = reader;
        this.resource = resource;
        // 初始化 Mapper 构建辅助类
        this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
    }

    /**
     * 解析 Mapper XML 文件，将文件中的 SQL 语句配置转换为 MappedStatement 对象
     * 并添加到 Configuration 中
     */
    @SneakyThrows
    public void parse() {
        // 创建 SAXReader 对象，用于解析 XML 文件
        SAXReader saxReader = new SAXReader();
        Document mapperDoc;
        try {
            // 读取 XML 文件并解析为 Document 对象
            mapperDoc = saxReader.read(new InputSource(reader));
        } catch (DocumentException e) {
            // 若解析失败，抛出运行时异常
            throw new RuntimeException(e);
        }
        // 获取 XML 文件的根元素
        Element mapperRoot = mapperDoc.getRootElement();
        // 获取命名空间属性值
        String namespace = mapperRoot.attributeValue("namespace");

        // 检查命名空间是否为空，若为空则抛出异常
        if (namespace == null || namespace.trim().isEmpty()) {
            throw new IllegalArgumentException("Namespace cannot be empty in " + resource);
        }
        // 设置当前命名空间
        builderAssistant.setCurrentNamespace(namespace);
        // 存储不同类型 SQL 语句元素的列表
        List<List<Element>> statements = new java.util.ArrayList<>();
        // 添加 <select> 元素列表
        statements.add(mapperRoot.elements("select"));
        // 添加 <insert> 元素列表
        statements.add(mapperRoot.elements("insert"));
        // 添加 <update> 元素列表
        statements.add(mapperRoot.elements("update"));
        // 添加 <delete> 元素列表
        statements.add(mapperRoot.elements("delete"));
        // 从 XML 元素列表中构建 SQL 语句
        buildStatementFromContext(statements);
        // 将 Mapper 接口类添加到 Configuration 中
        configuration.addMapper(Resources.classForName(builderAssistant.getCurrentNamespace()));
    }

    /**
     * 从 XML 元素列表中构建 SQL 语句，将每个 SQL 元素转换为 MappedStatement 对象
     *
     * @param elementLists 包含不同类型 SQL 语句元素的列表
     */
    private void buildStatementFromContext(List<List<Element>> elementLists) {
        // 遍历不同类型 SQL 语句元素列表
        for (List<Element> list : elementLists) {
            // 遍历每个 SQL 语句元素
            for (Element element : list) {
                // 创建 XMLStatementBuilder 对象，用于解析单个 SQL 语句节点
                final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, element);
                // 解析 SQL 语句节点
                statementParser.parseStatementNode();
            }
        }
    }
}